﻿using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using Abp.Linq.Extensions;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SingleUserMall.Common
{
    public static class ResultExtension
    {
        public static ListResultDto<T> ToListResultDto<M, T>(this IEnumerable<M> list)
        {
            return new ListResultDto<T>(list.MapTo<List<T>>());
        }

        public static async Task<PagedResultDto<T>> ToPagedResultDtoAsync<M, T>(this IQueryable<M> query, IPagedResultRequest page, Action<M, T> action = null)
        {
            var list = await query.PageBy(page).ToListAsync();
            var count = await query.CountAsync();
            var result = new List<T>();
            if (action == null)
            {
                result = list.MapTo<List<T>>();
            }
            else
            {
                foreach (var item in list)
                {
                    var _item = item.MapTo<T>();
                    action(item, _item);
                    result.Add(_item);
                }
            }
            return new PagedResultDto<T>(count, result);
        }

        public static async Task<PagedResultDto<T>> ToPagedResultDtoAsync<M, T>(this IQueryable<M> query, IPagedResultRequest page, Func<M, T, Task> func)
        {
            var list = await query.PageBy(page).ToListAsync();
            var count = await query.CountAsync();
            var result = new List<T>();
            foreach (var item in list)
            {
                var _item = item.MapTo<T>();
                await func(item, _item);
                result.Add(_item);
            }
            return new PagedResultDto<T>(count, result);
        }

        public static async Task<ListResultDto<T>> ToListResultDtoAsync<M, T>(this IQueryable<M> query, Action<M, T> action = null)
        {
            var list = await query.ToListAsync();
            var result = new List<T>();
            if (action == null)
            {
                result = list.MapTo<List<T>>();
            }
            else
            {
                foreach (var item in list)
                {
                    var _item = item.MapTo<T>();
                    action(item, _item);
                    result.Add(_item);
                }
            }
            return new ListResultDto<T>(result);
        }

        public static async Task<ListResultDto<T>> ToListResultDtoAsync<M, T>(this IQueryable<M> query, Func<M, T, Task> func)
        {
            var list = await query.ToListAsync();
            var result = new List<T>();
            foreach (var item in list)
            {
                var _item = item.MapTo<T>();
                await func(item, _item);
                result.Add(_item);
            }
            return new ListResultDto<T>(result);
        }

        public static T ToVO<M, T>(this M obj, Action<M, T> action = null)
        {
            var result = obj.MapTo<T>();
            if (obj != null)
                action?.Invoke(obj, result);
            return result;
        }

        public static List<T> ToListVO<M, T>(this IEnumerable<M> list, Action<M, T> action = null)
        {
            if (action != null)
            {
                var result = new List<T>();
                foreach (var obj in list)
                {
                    var r = obj.MapTo<T>();
                    action(obj, r);
                    result.Add(r);
                }
                return result;
            }
            else
            {
                return list.MapTo<List<T>>();
            }
        }

        public static async Task SaveAsync<M, TPrimaryKey, F>(this IRepository<M, TPrimaryKey> repository
            , F form, Action<M> beforeSave, Action<M> afterSave)
            where M : class, IEntity<TPrimaryKey>
            where F : EntityDto<TPrimaryKey>
        {
            var item = await repository.FirstOrDefaultAsync(form.Id);
            if (item != null)
            {
                item = form.MapTo(item);
                beforeSave?.Invoke(item);
                item = await repository.UpdateAsync(item);
                afterSave?.Invoke(item);
            }
            else
            {
                item = form.MapTo<M>();
                beforeSave?.Invoke(item);
                var id = await repository.InsertAndGetIdAsync(item);
                afterSave?.Invoke(await repository.FirstOrDefaultAsync(id));
            }
        }
    }
}
